package com.test.qpbgboot.schedule.service.impl;

import com.test.qpbgboot.base.enums.EnumController;
import com.test.qpbgboot.base.enums.EscortStatusEnum;
import com.test.qpbgboot.base.enums.GeneralStatusEnum;
import com.test.qpbgboot.base.enums.RoomStatusEnum;
import com.test.qpbgboot.base.exception.ServiceException;
import com.test.qpbgboot.base.response.ResultStatus;
import com.test.qpbgboot.schedule.mapper.EscortScheduleMapper;
import com.test.qpbgboot.schedule.mapper.RoomScheduleMapper;
import com.test.qpbgboot.schedule.pojo.dto.EscortScheduleQuery;
import com.test.qpbgboot.schedule.pojo.dto.EscortScheduleSaveParam;
import com.test.qpbgboot.schedule.pojo.dto.RoomScheduleQuery;
import com.test.qpbgboot.schedule.pojo.dto.RoomScheduleSaveParam;
import com.test.qpbgboot.schedule.pojo.entity.EscortSchedule;
import com.test.qpbgboot.schedule.pojo.entity.OrderInfo;
import com.test.qpbgboot.schedule.pojo.entity.RoomSchedule;
import com.test.qpbgboot.schedule.pojo.vo.EscortScheduleVO;
import com.test.qpbgboot.schedule.pojo.vo.RoomScheduleVO;
import com.test.qpbgboot.schedule.service.ScheduleService;
import com.test.qpbgboot.show.mapper.EscortMapper;
import com.test.qpbgboot.show.mapper.RoomMapper;
import com.test.qpbgboot.show.pojo.dto.EscortQuery;
import com.test.qpbgboot.show.pojo.dto.RoomQuery;
import com.test.qpbgboot.show.pojo.vo.EscortVO;
import com.test.qpbgboot.show.pojo.vo.RoomVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class ScheduleServiceImpl implements ScheduleService {

    @Autowired
    private RoomScheduleMapper roomScheduleMapper;
    @Autowired
    private EscortScheduleMapper escortScheduleMapper;
    @Autowired
    private RoomMapper roomMapper;
    @Autowired
    private EscortMapper escortMapper;

    @Override
    public List<RoomScheduleVO> roomScheduleSelect(RoomScheduleQuery roomScheduleQuery) {
        log.debug("房间排班查询业务，参数:{}", roomScheduleQuery);
        List<RoomScheduleVO> roomScheduleVOList = roomScheduleMapper
                .selectRoomScheduleVObyRoomScheduleQuery(roomScheduleQuery);
        log.debug("房间排班结果:{}", roomScheduleVOList);
        return roomScheduleVOList;
    }

    @Override
    public void roomScheduleSave(RoomScheduleSaveParam roomScheduleSaveParam) {
        log.debug("房间排班保存业务，参数:{}", roomScheduleSaveParam);

        if (!EnumController.checkContain(roomScheduleSaveParam
                .getStatus(), "RoomStatus")) {
            throw new ServiceException(ResultStatus.INCORRECT_STATUS);
        }
        if (!roomMapper.checkEnableById(
                roomScheduleSaveParam.getRoomId())) {
            throw new ServiceException(ResultStatus.INVALID_ID, "房间id无效");
        }

        RoomScheduleQuery roomScheduleQuery = new RoomScheduleQuery();
        BeanUtils.copyProperties(roomScheduleSaveParam, roomScheduleQuery);
        roomScheduleQuery.setStartDate(roomScheduleSaveParam.getScheduleDate());
        roomScheduleQuery.setEndDate(roomScheduleSaveParam.getScheduleDate());
        roomScheduleQuery.setStatus(null);
        roomScheduleQuery.setOrderId(null);
        List<RoomScheduleVO> roomScheduleVOList = roomScheduleMapper
                .selectRoomScheduleVObyRoomScheduleQuery(roomScheduleQuery);

        List<RoomSchedule> roomScheduleList = new ArrayList<>();
        RoomSchedule roomSchedule = new RoomSchedule();
        BeanUtils.copyProperties(roomScheduleSaveParam, roomSchedule);
        roomScheduleList.add(roomSchedule);

        if (roomScheduleVOList != null && !roomScheduleVOList.isEmpty()) {
            for (RoomScheduleVO roomScheduleVO : roomScheduleVOList) {
                LocalTime itemStartTime = roomScheduleVO.getStartTime();
                LocalTime itemEndTime = roomScheduleVO.getEndTime();
                LocalTime startTime = roomScheduleSaveParam.getStartTime();
                LocalTime endTime = roomScheduleSaveParam.getEndTime();
                boolean same = roomScheduleVO.getStatus()
                        .equals(roomScheduleSaveParam.getStatus())
                        && Objects.equals(roomScheduleVO.getOrderId(),
                        roomScheduleSaveParam.getOrderId());
                if (itemStartTime.isBefore(startTime)
                        && !itemEndTime.isAfter(endTime)) {
                    if (same) {
                        if (roomSchedule.getId() == null) {
                            roomSchedule.setId(roomScheduleVO.getId());
                        } else {
                            roomScheduleMapper.deleteById(roomScheduleVO.getId());
                        }
                        roomSchedule.setStartTime(itemStartTime);
                    } else {
                        RoomSchedule roomScheduleBefore = new RoomSchedule();
                        BeanUtils.copyProperties(roomScheduleVO, roomScheduleBefore);
                        roomScheduleBefore.setEndTime(startTime);
                        roomScheduleList.add(roomScheduleBefore);
                    }
                } else if (itemEndTime.isAfter(endTime)
                        && !itemStartTime.isBefore(startTime)) {
                    if (same) {
                        if (roomSchedule.getId() == null) {
                            roomSchedule.setId(roomScheduleVO.getId());
                        } else {
                            roomScheduleMapper.deleteById(roomScheduleVO.getId());
                        }
                        roomSchedule.setEndTime(itemEndTime);
                    } else {
                        RoomSchedule roomScheduleAfter = new RoomSchedule();
                        BeanUtils.copyProperties(roomScheduleVO, roomScheduleAfter);
                        roomScheduleAfter.setStartTime(endTime);
                        roomScheduleList.add(roomScheduleAfter);
                    }
                } else if (!itemStartTime.isBefore(startTime)
                        && !itemEndTime.isAfter(endTime)) {
                    roomScheduleMapper.deleteById(roomScheduleVO.getId());
                } else {
                    if (same) {
                        roomScheduleList.remove(roomSchedule);
                    } else {
                        RoomSchedule roomScheduleBefore = new RoomSchedule();
                        BeanUtils.copyProperties(roomScheduleVO, roomScheduleBefore);
                        roomScheduleBefore.setEndTime(startTime);
                        roomScheduleList.add(roomScheduleBefore);
                        RoomSchedule roomScheduleAfter = new RoomSchedule();
                        BeanUtils.copyProperties(roomScheduleVO, roomScheduleAfter);
                        roomScheduleAfter.setId(null);
                        roomScheduleAfter.setStartTime(endTime);
                        roomScheduleList.add(roomScheduleAfter);
                    }
                }
            }
        }
        if (!roomScheduleList.isEmpty()) {
            for (RoomSchedule schedule : roomScheduleList) {
                if (schedule.getId() == null) {
                    roomScheduleMapper.insert(schedule);
                } else {
                    roomScheduleMapper.update(schedule);
                }
            }
        }
    }

    @Override
    public List<EscortScheduleVO> escortScheduleSelect(EscortScheduleQuery escortScheduleQuery) {
        log.debug("陪玩排班查询业务，参数:{}", escortScheduleQuery);
        List<EscortScheduleVO> escortScheduleVOList = escortScheduleMapper
                .selectEscortScheduleVObyEscortScheduleQuery(escortScheduleQuery);
        log.debug("陪玩排班查询结果:{}", escortScheduleVOList);
        return escortScheduleVOList;
    }

    @Override
    public void escortScheduleSave(EscortScheduleSaveParam escortScheduleSaveParam) {
        log.debug("陪玩排班保存业务，参数:{}", escortScheduleSaveParam);

        if (!EnumController.checkContain(escortScheduleSaveParam
                .getStatus(), "EscortStatus")) {
            throw new ServiceException(ResultStatus.INCORRECT_STATUS);
        }
        if (!escortMapper.checkEnableById(
                escortScheduleSaveParam.getEscortId())) {
            throw new ServiceException(ResultStatus.INVALID_ID, "陪玩id无效");
        }

        EscortScheduleQuery escortScheduleQuery = new EscortScheduleQuery();
        BeanUtils.copyProperties(escortScheduleSaveParam, escortScheduleQuery);
        escortScheduleQuery.setStartDate(escortScheduleSaveParam.getScheduleDate());
        escortScheduleQuery.setEndDate(escortScheduleSaveParam.getScheduleDate());
        escortScheduleQuery.setStatus(null);
        escortScheduleQuery.setOrderId(null);
        List<EscortScheduleVO> escortScheduleVOList = escortScheduleMapper
                .selectEscortScheduleVObyEscortScheduleQuery(escortScheduleQuery);

        List<EscortSchedule> escortScheduleList = new ArrayList<>();
        EscortSchedule escortSchedule = new EscortSchedule();
        BeanUtils.copyProperties(escortScheduleSaveParam, escortSchedule);
        escortScheduleList.add(escortSchedule);

        if (escortScheduleVOList != null && !escortScheduleVOList.isEmpty()) {
            for (EscortScheduleVO escortScheduleVO : escortScheduleVOList) {
                LocalTime itemStartTime = escortScheduleVO.getStartTime();
                LocalTime itemEndTime = escortScheduleVO.getEndTime();
                LocalTime startTime = escortSchedule.getStartTime();
                LocalTime endTime = escortSchedule.getEndTime();
                boolean same = escortSchedule.getStatus()
                        .equals(escortScheduleVO.getStatus())
                        && Objects.equals(escortSchedule.getOrderId(),
                        escortScheduleVO.getOrderId());
                if (itemStartTime.isBefore(startTime)
                        && !itemEndTime.isAfter(endTime)) {
                    if (same) {
                        if (escortSchedule.getId() == null) {
                            escortSchedule.setId(escortScheduleVO.getId());
                        } else {
                            roomScheduleMapper.deleteById(escortScheduleVO.getId());
                        }
                        escortSchedule.setStartTime(itemStartTime);
                    } else {
                        EscortSchedule escortScheduleBefore = new EscortSchedule();
                        BeanUtils.copyProperties(escortScheduleVO, escortScheduleBefore);
                        escortScheduleBefore.setEndTime(startTime);
                        escortScheduleList.add(escortScheduleBefore);
                    }
                } else if (itemEndTime.isAfter(endTime)
                        && !itemStartTime.isBefore(startTime)) {
                    if (same) {
                        if (escortSchedule.getId() == null) {
                            escortSchedule.setId(escortScheduleVO.getId());
                        } else {
                            escortScheduleMapper.deleteById(escortScheduleVO.getId());
                        }
                        escortSchedule.setEndTime(itemEndTime);
                    } else {
                        EscortSchedule escortScheduleAfter = new EscortSchedule();
                        BeanUtils.copyProperties(escortScheduleVO, escortScheduleAfter);
                        escortScheduleAfter.setStartTime(endTime);
                        escortScheduleList.add(escortScheduleAfter);
                    }
                } else if (!itemStartTime.isBefore(startTime)
                        && !itemEndTime.isAfter(endTime)) {
                    escortScheduleMapper.deleteById(escortScheduleVO.getId());
                } else {
                    if (same) {
                        escortScheduleList.remove(escortSchedule);
                    } else {
                        EscortSchedule escortScheduleBefore = new EscortSchedule();
                        BeanUtils.copyProperties(escortScheduleVO, escortScheduleBefore);
                        escortScheduleBefore.setEndTime(startTime);
                        escortScheduleList.add(escortScheduleBefore);
                        EscortSchedule escortScheduleAfter = new EscortSchedule();
                        BeanUtils.copyProperties(escortScheduleVO, escortScheduleAfter);
                        escortScheduleAfter.setId(null);
                        escortScheduleAfter.setStartTime(endTime);
                        escortScheduleList.add(escortScheduleAfter);
                    }
                }
            }
        }
        if (!escortScheduleList.isEmpty()) {
            for (EscortSchedule schedule : escortScheduleList) {
                if (schedule.getId() == null) {
                    escortScheduleMapper.insert(schedule);
                } else {
                    escortScheduleMapper.update(schedule);
                }
            }
        }
    }

    @Override
    public void checkRoomSchedule(Long roomId, LocalDate appointmentDate,
                                  LocalTime startTime, LocalTime endTime) {
        log.debug("确认房间排班业务，参数:{},{},{},{}",
                roomId, appointmentDate, startTime, endTime);
        RoomScheduleQuery roomScheduleQuery = new RoomScheduleQuery();
        roomScheduleQuery.setRoomId(roomId);
        roomScheduleQuery.setStartDate(appointmentDate);
        roomScheduleQuery.setEndDate(appointmentDate);
        roomScheduleQuery.setStartTime(startTime);
        roomScheduleQuery.setEndTime(endTime);
        roomScheduleQuery.setStatus(RoomStatusEnum.AVAILABLE.getValue());
        if (roomScheduleMapper
                .selectEnableByRoomScheduleQuery(roomScheduleQuery) !=1) {
            throw new ServiceException(ResultStatus.SCHEDULE_NOT_ALLOWED,"房间排班不允许");
        }
    }

    @Override
    public void checkRoomSchedule(OrderInfo orderInfo) {
        Long roomId = orderInfo.getRoomId();
        if (roomId == null) {
            return;
        }
        LocalDate appointmentDate = orderInfo.getAppointmentDate();
        LocalTime startTime = orderInfo.getStartTime();
        LocalTime endTime = orderInfo.getEndTime();
        checkRoomSchedule(roomId, appointmentDate, startTime, endTime);
    }

    @Override
    public void checkEscortSchedule(Long escortId, LocalDate appointmentDate,
                                    LocalTime startTime, LocalTime endTime) {
        log.debug("检查陪玩排班冲突业务，参数:{},{},{},{}",
                escortId, appointmentDate, startTime, endTime);
        EscortScheduleQuery escortScheduleQuery = new EscortScheduleQuery();
        escortScheduleQuery.setEscortId(escortId);
        escortScheduleQuery.setStartDate(appointmentDate);
        escortScheduleQuery.setEndDate(appointmentDate);
        escortScheduleQuery.setStartTime(startTime);
        escortScheduleQuery.setEndTime(endTime);
        escortScheduleQuery.setStatus(EscortStatusEnum.FREE.getValue());
        if (escortScheduleMapper
                .selectEnableByEscortScheduleQuery(escortScheduleQuery) != 1) {
            throw new ServiceException(ResultStatus.SCHEDULE_NOT_ALLOWED,"陪玩排班不允许");
        }
    }

    @Override
    public void checkEscortSchedule(OrderInfo orderInfo) {
        log.debug("检查陪玩排班冲突业务，参数:{}", orderInfo);
        List<Long> escortIdList = orderInfo.getEscortIdList();
        LocalDate appointmentDate = orderInfo.getAppointmentDate();
        LocalTime startTime = orderInfo.getStartTime();
        LocalTime endTime = orderInfo.getEndTime();
        if (escortIdList == null || escortIdList.isEmpty()) {
            return;
        }
        for (Long escortId: escortIdList) {
            checkEscortSchedule(escortId, appointmentDate, startTime, endTime);
        }
    }

    @Override
    public void roomAndEscortScheduleGenerate() {
        log.debug("生成房间和陪玩排班-业务");

        LocalDate today = LocalDate.now();
        int dayFrom = 14;//排班的日期从14天后开始（包括第14天）
        int dayTo = 21;//排班的日期到21天后结束（不包括第21天）

        RoomQuery roomQuery = new RoomQuery();
        roomQuery.setVisible(GeneralStatusEnum.ENABLE.getValue());
        List<RoomVO> roomVOList = roomMapper.selectRoomVObyRoomQuery(roomQuery);
        
        if (roomVOList != null && !roomVOList.isEmpty()) {
            for(RoomVO roomVO: roomVOList) {
                LocalTime startTime = roomVO.getOpeningHoursFrom();
                LocalTime endTime = roomVO.getOpeningHoursTo();
                if (startTime == null || endTime == null) {
                    continue;
                }

                RoomSchedule roomSchedule = new RoomSchedule();
                roomSchedule.setRoomId(roomVO.getId());
                roomSchedule.setStartTime(startTime);
                roomSchedule.setEndTime(endTime);
                roomSchedule.setStatus(RoomStatusEnum.AVAILABLE.getValue());
                for (int i = dayFrom; i < dayTo; i++) {
                    roomSchedule.setScheduleDate(today.plusDays(i));
                    roomScheduleMapper.insert(roomSchedule);
                }
            }
        }

        EscortQuery escortQuery = new EscortQuery();
        escortQuery.setStatus(GeneralStatusEnum.ENABLE.getValue());
        escortQuery.setVisible(GeneralStatusEnum.ENABLE.getValue());
        List<EscortVO> escortVOList =
                escortMapper.selectEscortVObyEscortQuery(escortQuery);

        if (escortVOList != null && !escortVOList.isEmpty()) {
            for (EscortVO escortVO: escortVOList) {
                LocalTime startTime = escortVO.getWorkingHoursFrom();
                LocalTime endTime = escortVO.getWorkingHoursTo();
                if (startTime == null || endTime == null) {
                    continue;
                }

                EscortSchedule escortSchedule = new EscortSchedule();
                escortSchedule.setEscortId(escortVO.getId());
                escortSchedule.setStartTime(startTime);
                escortSchedule.setEndTime(endTime);
                escortSchedule.setStatus(EscortStatusEnum.FREE.getValue());

                for (int i = dayFrom; i < dayTo; i++) {
                    escortSchedule.setScheduleDate(today.plusDays(i));
                    escortScheduleMapper.insert(escortSchedule);
                }
            }
        }
    }

    /**
     * 每半小时更新房间排班表和陪玩排班表，
     * 将过期的已预约改成已使用或已工作
     */
    @Override
    public void refreshTable() {
        log.debug("刷新排班表-业务");

        roomScheduleMapper.refreshStatus();
        escortScheduleMapper.refreshStatus();
    }
}
